#define _CRT_SECURE_NO_WARNINGS
#include "Image.h"
#include <iostream>
#include <Windows.h>
#include <math.h>
<<<<<<< HEAD
=======

>>>>>>> 254f31facb65d7a054f082d9aca999c824df521e
using namespace std;
BITMAPFILEHEADER filehead;
BITMAPINFOHEADER infohead;
int bitCount;
RGBQUAD *pColorTable; //颜色表指针

//构造函数
Image::Image()
{
	cout << "调用默认构造函数成功" << endl;
}

//构造函数重载
Image::Image(int h, int w)
{
	height = h;
	width = w;
	linebyte = h * w;
	data = new unsigned char[linebyte];
	for (int i = 0; i < linebyte; i++)
		data[i] = 0;
	cout << "调用构造函数成功" << endl;
}
Image::Image(int h, int w, unsigned char val)
{
	height = h;
	width = w;
	linebyte = h * w;
	data = new unsigned char[linebyte];
	for (int i = 0; i < linebyte; i++)
		data[i] = val;
	cout << "调用构造函数成功" << endl;
}
Image::Image(const char *ImageName)
{

	FILE *fp = fopen(ImageName, "rb");
	if (!fp)
	{
		cout << "Error!" << endl;
		exit(0);
	}
	fread(&filehead, sizeof(BITMAPFILEHEADER), 1, fp);
	fread(&infohead, sizeof(BITMAPINFOHEADER), 1, fp);
	width = infohead.biWidth;
	height = infohead.biHeight;
	bitCount = infohead.biBitCount;
	width = (width * bitCount / 8 + 3) / 4 * 4;
	linebyte = width * height;
	data = new unsigned char[linebyte];
	for (int i = 0; i < linebyte; i++)
		fread(&data[i], 1, 1, fp);

	//灰度图像有颜色表，且颜色表表项为256
	if (bitCount == 8)
	{
		//申请颜色表所需要的空间，读颜色表进内存
		pColorTable = new RGBQUAD[256];
		fread(pColorTable, sizeof(RGBQUAD), 256, fp);
	}
	fclose(fp);
	cout << "调用构造函数成功" << endl;
}

Image::Image(unsigned char *m, int h, int w)
{
	height = h;
	width = w;
	linebyte = width * height;
	data = new unsigned char[linebyte];
	for (int i = 0; i < linebyte; i++)
		data[i] = m[i];
	cout << "调用构造函数成功" << endl;
}

Image::Image(const Image &im)
{
	height = im.height;
	width = im.width;
	linebyte = width * height;
	data = new unsigned char[linebyte];
	for (int i = 0; i < linebyte; i++)
		data[i] = im.data[i];
	cout << "调用拷贝构造函数成功" << endl;
}

Image::~Image()
{
	cout << "已调用析构函数" << endl;
}

//读取BMP文件的图像
void Image::ReadBMP(const char *filename)
{

    FILE *fp = fopen(filename, "rb");
	if (!fp)
	{
		cout << "Error!" << endl;
		exit(0);
	}
	fread(&filehead, sizeof(BITMAPFILEHEADER), 1, fp);
	fread(&infohead, sizeof(BITMAPINFOHEADER), 1, fp);
    width = infohead.biWidth;
	height = infohead.biHeight;
	bitCount = infohead.biBitCount;
    width = (width * bitCount / 8 + 3) / 4 * 4;
    //linebyte = (real_width*3+2)  * height;

    linebyte = width*height;
	data = new unsigned char[linebyte];
	for (int i = 0; i < linebyte; i++)
		fread(&data[i], 1, 1, fp);

	//灰度图像有颜色表，且颜色表表项为256
	if (bitCount == 8)
	{
		//申请颜色表所需要的空间，读颜色表进内存
		pColorTable = new RGBQUAD[256];
		fread(pColorTable, sizeof(RGBQUAD), 256, fp);
	}
	fclose(fp);
    cout << "调用构造函数成功" << endl;
}

//将图像写入BMP文件
void Image::WriteBMP(const char *filename)
{

	FILE *wfp = fopen(filename, "wb");
	//颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0
	int colorTablesize = 0;
	if (bitCount == 8)
		colorTablesize = 1024;

	//申请位图文件头结构变量，填写文件头信息
	filehead.bfType = 0x4D42; // bmp类型

	// bfSize是图像文件4个组成部分之和
	filehead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + width * height;
	filehead.bfReserved1 = 0;
	filehead.bfReserved2 = 0;

	// bfOffBits是图像文件前三个部分所需空间之和
	filehead.bfOffBits = 54 + colorTablesize;

	//写文件头进文件
	fwrite(&filehead, sizeof(BITMAPFILEHEADER), 1, wfp);
	//申请位图信息头结构变量，填写信息头信息
	infohead.biBitCount = bitCount;
	infohead.biClrImportant = 0;
	infohead.biClrUsed = 0;
	infohead.biCompression = 0;
	infohead.biHeight = height;
	infohead.biPlanes = 1;
	infohead.biSize = 40;
	infohead.biSizeImage = width * height;
	infohead.biWidth = width / 3;
	infohead.biXPelsPerMeter = 0;
	infohead.biYPelsPerMeter = 0;
	fwrite(&infohead, sizeof(BITMAPINFOHEADER), 1, wfp);

	//如果灰度图像,有颜色表,写入文件
	if (bitCount == 8)
		fwrite(pColorTable, sizeof(RGBQUAD), 256, wfp);

	fwrite(data, linebyte, 1, wfp);
	fclose(wfp);

	cout << "图片写入成功！" << endl;
}

//翻转
void Image::Flip(int code)
{
	unsigned char **flip = new unsigned char *[height];
	for (int i = 0; i < height; i++)
		flip[i] = new unsigned char[width];
	int n = 0;
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j++, n++)
			flip[i][j] = data[n];
	if (code)
	{
		int i = height - 1, j = 0;
		while (j < i)
		{
			unsigned char *temp = flip[i];
			flip[i] = flip[j];
			flip[j] = temp;
			i--;
			j++;
		}
		n = 0;
		for (int i = 0; i < height; i++)
			for (int j = 0; j < width; j++, n++)
				data[n] = flip[i][j];
		cout << "上下翻转成功！" << endl;
	}
	else
	{
		for (int i = 0; i < height; i++)
		{
			int j = 0, k = width - 1;
			while (j < k)
			{
				unsigned char temp = flip[i][j + 2];
				flip[i][j + 2] = flip[i][k];
				flip[i][k] = temp;
				temp = flip[i][j + 1];
				flip[i][j + 1] = flip[i][k - 1];
				flip[i][k - 1] = temp;
				temp = flip[i][j];
				flip[i][j] = flip[i][k - 2];
				flip[i][k - 2] = temp;
				j += 3;
				k -= 3;
			}
		}
		n = 0;
		for (int i = 0; i < height; i++)
			for (int j = 0; j < width; j++, n++)
				data[n] = flip[i][j];
		cout << "左右翻转成功！" << endl;
	}
	for (int i = 0; i < height; i++)
		delete[] flip[i];
	delete[] flip;
}
//放缩
void Image::Resize(int h, int w)
{
	int ht = h / height;
	int wt = w * 3 / width;
	unsigned char **temp = new unsigned char *[h];
	for (int i = 0; i < h; i++)
		temp[i] = new unsigned char[w * 3];
	unsigned char **resize = new unsigned char *[height];
	for (int i = 0; i < height; i++)
		resize[i] = new unsigned char[width];
	int uu = 0;
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j++, uu++)
			resize[i][j] = data[uu];
	if (ht < 1)
	{
		for (int i = 0, m = 0; i < h; i++, m += height / h)
		{
			if (wt < 1)
				for (int j = 0, n = 0; j < w * 3; j++, n += width / (w * 3))
					temp[i][j] = resize[m][n];
			else
				for (int j = 0; j < width; j++)
					for (int x = 0; x < wt; x++)
						temp[i][j * wt + x] = resize[m][j];
		}
	}
	else
	{
		for (int i = 0; i < height; i++)
			for (int x = 0; x < ht; x++)
			{
				if (wt < 1)
					for (int j = 0, n = 0; j < w * 3; j++, n += width / (w * 3))
						temp[i * ht + x][j] = resize[i][n];
				else
					for (int j = 0; j < w * 3; j++)
						for (int y = 0; y < wt; x++)
							temp[i * ht + x][j * wt + y] = resize[i][j];
			}
	}
	delete[] data;
	height = h;
	width = w * 3;
	linebyte = width * height;
	data = new unsigned char[linebyte];
	uu = 0;
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j++, uu++)
			data[uu] = temp[i][j];
	for (int i = 0; i < height; i++)
		delete[] temp[i];
	delete[] temp;
	for (int i = 0; i < height; i++)
		delete[] resize[i];
	delete[] resize;
	cout << "放缩成功！" << endl;
}
//裁剪
Image Image::Cut(int x1, int y1, int x2, int y2)
{
	unsigned char **ti = new unsigned char *[height];
	for (int i = 0; i < height; i++)
		ti[i] = new unsigned char[width];
	int uu = 0;
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j++, uu++)
			ti[i][j] = data[uu];
	long h = height;
	long w = width;
	//计算裁剪后的尺寸
	w /= 3;
	h = y2 < y1 ? y1 - y2 : y2 - y1;
	w = x2 < x1 ? x1 - x2 : x2 - x1;
	w *= 3;
	Image crop(h, w);
	unsigned char **to = new unsigned char *[h];
	for (int i = 0; i < h; i++)
		to[i] = new unsigned char[w];
	uu = 0;
	for (int i = 0; i < h; i++)
		for (int j = 0; j < w; j++, uu++)
			to[i][j] = crop.data[uu];
	//计算起始点
	int x = x1 < x2 ? x1 : x2;
	int y = y1 < y2 ? y1 : y2;
	for (int m = 0; m < h; m++)
		for (int n = 0; n < w; n++)
			to[m][n] = ti[m + y][n + x];
	uu = 0;
	for (int i = 0; i < h; i++)
		for (int j = 0; j < w; j++, uu++)
			crop.data[uu] = to[i][j];
	for (int i = 0; i < height; i++)
		delete[] ti[i];
	delete[] ti;
	for (int i = 0; i < h; i++)
		delete[] to[i];
	delete[] to;
	cout << "裁剪成功！" << endl;
	return crop;
}
//旋转
void Image::Rotate(int degree)
{

	for (int n = 0; n < fabs(degree / 90); n++)
	{
		unsigned char **rotate = new unsigned char *[height];
		for (int i = 0; i < height; i++)
			rotate[i] = new unsigned char[width];
		int uu = 0;
		for (int i = 0; i < height; i++)
			for (int j = 0; j < width; j++, uu++)
				rotate[i][j] = data[uu];
		unsigned char **r = new unsigned char *[width / 3];
		for (int i = 0; i < width / 3; i++)
			r[i] = new unsigned char[height * 3];
		for (int i = 0, k = width - 1; k > 0; i++, k -= 3)
			for (int j = 0; j < height; j++)
			{
				// cout << j<<" "<<k << endl;
				r[i][j * 3] = rotate[j][k - 2];
				r[i][j * 3 + 1] = rotate[j][k - 1];
				r[i][j * 3 + 2] = rotate[j][k];
			}
		delete[] data;
		int temp = width / 3;
		width = height * 3;
		height = temp;
		linebyte = width * height;
		data = new unsigned char[linebyte];
		uu = 0;
		for (int i = 0; i < height; i++)
			for (int j = 0; j < width; j++, uu++)
				data[uu] = r[i][j];
		for (int i = 0; i < height; i++)
			delete[] r[i];
		delete[] r;
		for (int i = 0; i < height; i++)
			delete[] rotate[i];
		delete[] rotate;
	}

	cout << "旋转成功！" << endl;
}
//求平均值
double Image::Mean()
{
	double m = 0;
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j++)
			m += (double)data[i * width + j];
	m /= height * width;
	return m;
}

double Image::Variance()
{
	double m = 0, var = 0;
	for (int i = 0; i < linebyte; i++)
		m += (double)data[i];
	m /= height * width;
	for (int i = 0; i < linebyte; i++)
		var += (data[i] - m) * (data[i] - m);
	var /= height * width;
	return var;
}

Image Image::operator-() //对象图像取反，把所有像素的值都规整到[0,1]之间，然后每个像素都被1.0减
{
	double *x = new double[linebyte];

	for (int i = 0; i < linebyte; i++)
		x[i] = (double)data[i];
	for (int i = 0; i < linebyte; i++)
	{

		x[i] = x[i] / 255;
		x[i] = 1 - x[i];
		x[i] = x[i] * 255;

		data[i] = (unsigned char)x[i];
	}

	delete[] x;
	cout << "图像取反成功" << endl;

	return *this;
}
void Image::gray2bw(double t) //以给定阈值t对图像进行二值化，返回图像对象
{
	for (int i = 0; i < linebyte; i++)
	{
		data[i] = data[i] < (unsigned char)t ? 0 : 1;
		data[i] *= 255;
	}

	cout << "图像二值化成功" << endl;
	// return *this;
}
void Image::Grayed()
{
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j += 3)
		{
			unsigned char temp = (data[i * width + j + 2] + data[i * width + j + 1] + data[i * width + j]) / 3;
			data[i * width + j] = temp;
			data[i * width + j + 1] = temp;
			data[i * width + j + 2] = temp;
		}
}
Image Image::gradient() //边缘检测
{
	Image out(height, width);

	// 初始化
	Grayed();
	for (int i = 0; i < height; ++i)
	{
		for (int j = 0; j < width; ++j)
		{
			*(out.data + i * width + j) = *(data + i * width + j);
		}
	}

	int ul, uc, ur, dl, dc, dr;
	int lu, lc, ld, ru, rc, rd;
	double hir, vec;
	for (int i = 1; i < height - 1; ++i)
	{
		for (int j = 1; j < width - 1; ++j)
		{
			// 垂直梯度算子：检测水平边缘
			vec = 0;
			ul = *(data + (i + 1) * width + (j - 1)) * (-1);
			uc = *(data + (i + 1) * width + j) * (-2);
			ur = *(data + (i + 1) * width + j) * (-1);
			dl = *(data + (i - 1) * width + (j - 1)) * 1;
			dc = *(data + (i - 1) * width + j) * 2;
			dr = *(data + (i - 1) * width + j) * 1;
			vec = ul + uc + ur + dl + dc + dr;
			// 水平梯度算子：检测垂直边缘
			hir = 0;
			lu = *(data + (i + 1) * width + (j - 1)) * (-1);
			lc = *(data + (i - 0) * width + (j - 1)) * (-2);
			ld = *(data + (i - 1) * width + (j - 1)) * (-1);
			ru = *(data + (i + 1) * width + (j + 1)) * 1;
			rc = *(data + (i - 0) * width + (j + 1)) * 2;
			rd = *(data + (i - 1) * width + (j + 1)) * 1;
			hir = lu + lc + ld + ru + rc + rd;
			*(out.data + i * width + j) = round(sqrt(hir * hir + vec * vec));
		}
	}
	out.Grayed();
	return out;
}

Image Image::Cat(Image &m, int code) // 将矩阵m与当前矩阵进行拼接，code代表拼接的方式：将m拼接到当前矩阵的上、下、左、右，具体例子见本大纲后面的说明
{
	switch (code)
	{
	case 1: //上
	{
		int w = m.width < width ? m.width : width;

		Image cat(height + m.height, w);
		int i = 0, x = 0, y = 0;
		for (i, x; i < cat.linebyte; i++, x++)
		{
			if (x < m.linebyte)
				cat.data[i] = m.data[x];
			else
			{
				cat.data[i] = data[y];
				y++;
			}
		}
		cout << "矩阵上接成功！" << endl;
		/*width = w;
		height = height + m.height;
		data = new double* [height];
		for (int i = 0;i < height;i++)
			data[i] = new double[width];
		for (int i = 0;i < height;i++)
			for (int j = 0;j < width;j++)
				data[i][j] = cat[i][j];*/
		return cat;
		break;
	}
	case 2: //下
	{
		int w = m.width < width ? m.width : width;
		Image cat(height + m.height, w);
		int i = 0, x = 0, y = 0;
		for (i, x; i < cat.linebyte; i++, x++)
		{
			if (x < linebyte)
				cat.data[i] = data[x];
			else
			{
				cat.data[i] = m.data[y];
				y++;
			}
		}
		cout << "矩阵下接成功！" << endl;
		return cat;
		break;
	}
	case 3: //左
	{
		int h = m.height < height ? m.height : height;
		Image cat(h, width + m.width);
		unsigned char **out = new unsigned char *[cat.height];
		for (int i = 0; i < cat.height; i++)
			out[i] = new unsigned char[cat.width];
		unsigned char **a = new unsigned char *[height];
		for (int i = 0; i < height; i++)
			a[i] = new unsigned char[width];
		unsigned char **b = new unsigned char *[m.height];
		for (int i = 0; i < m.height; i++)
			b[i] = new unsigned char[m.width];
		int uu = 0;
		for (int i = 0; i < height; i++)
			for (int j = 0; j < width; j++, uu++)
				a[i][j] = data[uu];
		uu = 0;
		for (int i = 0; i < m.height; i++)
			for (int j = 0; j < m.width; j++, uu++)
				b[i][j] = m.data[uu];
		for (int i = 0; i < h; i++)
		{
			int j = 0, x = 0, y = 0;
			for (j, y; j < width + m.width; j++, y++)
			{
				if (y < m.width)
					out[i][j] = b[i][y];
				else
				{
					out[i][j] = a[i][x];
					x++;
				}
			}
		}

		uu = 0;
		for (int i = 0; i < cat.height; i++)
			for (int j = 0; j < cat.width; j++, uu++)
				cat.data[uu] = out[i][j];
		for (int i = 0; i < height; i++)
			delete[] a[i];
		delete[] a;
		for (int i = 0; i < m.height; i++)
			delete[] b[i];
		delete[] b;
		for (int i = 0; i < cat.height; i++)
			delete[] out[i];
		delete[] out;
		cout << "矩阵左接成功！" << endl;
		return cat;
		break;
	}
	case 4: //右
	{
		int h = m.height < height ? m.height : height;
		Image cat(h, width + m.width);
		unsigned char **out = new unsigned char *[cat.height];
		for (int i = 0; i < cat.height; i++)
			out[i] = new unsigned char[cat.width];
		unsigned char **a = new unsigned char *[height];
		for (int i = 0; i < height; i++)
			a[i] = new unsigned char[width];
		unsigned char **b = new unsigned char *[m.height];
		for (int i = 0; i < m.height; i++)
			b[i] = new unsigned char[m.width];
		int uu = 0;
		for (int i = 0; i < height; i++)
			for (int j = 0; j < width; j++, uu++)
				a[i][j] = data[uu];
		uu = 0;
		for (int i = 0; i < m.height; i++)
			for (int j = 0; j < m.width; j++, uu++)
				b[i][j] = m.data[uu];
		for (int i = 0; i < h; i++)
		{
			int j = 0, x = 0, y = 0;
			for (j, y; j < width + m.width; j++, y++)
			{
				if (y < width)
					out[i][j] = a[i][y];
				else
				{
					out[i][j] = b[i][x];
					x++;
				}
			}
		}
		uu = 0;
		for (int i = 0; i < cat.height; i++)
			for (int j = 0; j < cat.width; j++, uu++)
				cat.data[uu] = out[i][j];
		for (int i = 0; i < height; i++)
			delete[] a[i];
		delete[] a;
		for (int i = 0; i < m.height; i++)
			delete[] b[i];
		delete[] b;
		for (int i = 0; i < cat.height; i++)
			delete[] out[i];
		delete[] out;
		return cat;
		cout << "矩阵右接成功！" << endl;
	}
	default:
		cout << "矩阵拼接code错误！" << endl;
		break;
	}
}
// Image Image::MeanFilter(int filtersize)
//{
//	unsigned char** mean = new unsigned char* [height];
//	for (int i = 0;i < height;i++)
//		mean[i] = new unsigned char[width];
//	int uu = 0;
//	for (int i = 0;i < height;i++)
//		for (int j = 0;j < width;j++, uu++)
//			mean[i][j] = data[uu];
//	int h = height;
//	int	w = width;
//	Image mtemp(h, w);
//	unsigned char sum, num;
//	int left, right, up, down;
//	for (int i = 0;i < h;i++)
//		for (int j = 0;j < w;j++)
//			mtemp.data[i*w+j] = data[i*w+j];
//	for (int i = 0;i < h;i++)
//		for (int j = 0;j < w;j++)
//		{
//			sum = 0;
//			num = 0;
//			left = j - filtersize / 2;
//			if (left < 0)
//				left = 0;
//			right = j + filtersize / 2;
//			if (right >= w)
//				right = w - 1;
//			up = i - filtersize / 2;
//			if (up < 0)
//				up = 0;
//			down = i + filtersize / 2;
//			if (down >= h)
//				down = h - 1;
//			int temp = left;
//			for (up;up <= down;up++)
//			{
//				left = temp;
//				for (left;left <= right;left++)
//				{
//					sum += mean[up][left];
//					num++;
//				}
//			}
//			mtemp.data[i*width+j] = sum / num;
//		}
//	for (int i = 0;i < height;i++)
//		delete[]mean[i];
//	delete[]mean;
//	return mtemp;
// }
// Image Image::MedianFilter(int filtersize)
//{
//	unsigned char** median = new unsigned char* [height];
//	for (int i = 0;i < height;i++)
//		median[i] = new unsigned char[width];
//	int uu = 0;
//	for (int i = 0;i < height;i++)
//		for (int j = 0;j < width;j++, uu++)
//			median[i][j] = data[uu];
//	Image mtemp(height, width);
//	int left, right, up, down;
//	for (int i = 0;i < height;i++)
//		for (int j = 0;j < width;j++)
//		{
//
//			left = j - filtersize / 2;
//			if (left < 0)
//				left = 0;
//			right = j + filtersize / 2;
//			if (right >= width)
//				right = width - 1;
//			up = i - filtersize / 2;
//			if (up < 0)
//				up = 0;
//			down = i + filtersize / 2;
//			if (down >= height)
//				down = height - 1;
//			int temp = left;
//			int lenth = (right - left + 1) * (down - up + 1);
//			double* Td = new double[lenth];
//			int d = 0;
//			for (up;up <= down;up++)
//			{
//				left = temp;
//				for (left;left <= right;left++, d++)
//					Td[d] =median[up][left];
//			}
//			for (int n = 0;n < lenth;n++)
//				for (int m = n + 1;m < lenth;m++)
//					if (Td[n] > Td[m])
//					{
//						double t = Td[n];
//						Td[n] = Td[m];
//						Td[m] = t;
//					}
//			mtemp.data[i*width+j] = Td[lenth / 2];
//			delete[]Td;
//		}
//	for (int i = 0;i < height;i++)
//		delete[]median[i];
//	delete[]median;
//	return mtemp;
// }
